package com.tre.jdevtemplateboot.common.redis.impl;

import com.tre.jdevtemplateboot.common.constant.SysConstantToken;
import com.tre.jdevtemplateboot.common.dto.PropertiesConfig;
import com.tre.jdevtemplateboot.common.enums.RefreshTokenEnums;
import com.tre.jdevtemplateboot.common.redis.IRedisTokenManagerService;
import com.tre.jdevtemplateboot.common.util.HttpUtils;
import com.tre.jdevtemplateboot.common.util.JwtUtils;
import com.tre.jdevtemplateboot.exception.business.SysInvalidTokenException;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author JDev
 */
@Service
public class TokenManagerServiceImpl implements IRedisTokenManagerService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private PropertiesConfig propertiesConfig;
    private String preFixUserId;

    @Override
    public String generateToken(String userId) {
        Map<String, Object> claims = new HashMap<>(16);
        claims.put(SysConstantToken.USER_ID_KEY, userId);
        HttpServletRequest request = HttpUtils.getHttpServletRequest();
        if (request != null) {
            String headerDeviceKey = propertiesConfig.getHeaderDeviceKey();
            String headerDeviceValue = request.getHeader(headerDeviceKey);
            if (!StringUtils.hasLength(headerDeviceValue)) {
                headerDeviceValue = request.getParameter(headerDeviceKey);
            }
            if (StringUtils.hasLength(headerDeviceValue)) {
                claims.put(headerDeviceKey, headerDeviceValue);
                userId = userId +SysConstantToken.USERID_SPLIT_MARKET_DEVICEID+ headerDeviceValue;
            }
        }
        String token = JwtUtils.createJwtToken(claims, 0L);
        preFixUserId = getPrefixUserId(userId);
        redisTemplate.opsForValue().set(preFixUserId, token, Long.parseLong(propertiesConfig.getTokenExpire()), TimeUnit.MILLISECONDS);
        return token;
    }

    @Override
    public String updateToken(String headerToken) {
        Claims claims = JwtUtils.getClaimsByToken(headerToken);
        String userId = (String) claims.get(SysConstantToken.USER_ID_KEY);
        String deviceId = (String) claims.get(propertiesConfig.getHeaderDeviceKey());
        if (StringUtils.hasLength(deviceId)){
            userId = userId +SysConstantToken.USERID_SPLIT_MARKET_DEVICEID+ deviceId;
        }
        preFixUserId = getPrefixUserId(userId);
        Object object = redisTemplate.opsForValue().get(preFixUserId);
        if (object == null || !object.equals(headerToken)) {
            throw new SysInvalidTokenException();
        }
        if (RefreshTokenEnums.TRUE.toString().equalsIgnoreCase(propertiesConfig.getRefreshToken())) {
            return generateToken(userId);
        }
        redisTemplate.expire(preFixUserId, Long.parseLong(propertiesConfig.getTokenExpire()), TimeUnit.MILLISECONDS);
        return headerToken;
    }

    private String getPrefixUserId(String userId) {
        return propertiesConfig.getPreUserSubject() + userId;
    }

}
